package com.fastloan.mgt.processcontrol.base.service;

import com.fastloan.mgt.application.base.model.ProcessFlow;
import com.fastloan.mgt.processcontrol.base.annotation.FunctionHandlerClass;
import com.fastloan.mgt.processcontrol.base.model.Process;
import com.fastloan.mgt.processcontrol.base.model.*;
import com.fastloan.mgt.processcontrol.base.util.AopTargetUtils;
import com.fastloan.mgt.processcontrol.base.util.BeanFactoryUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.fastloan.mgt.processcontrol.base.enums.ProcessConstant.DEFAULT_NEED_CLEAN_VALUE;

/**
 * 产品后续功能Service实现类
 *
 * @author yanwe
 *         createTime 2017-02-2017/2/14 9:33
 */
@Service
public class ProcessFunctionServiceImpl implements ProcessFunctionService {

    private static final Logger logger = LoggerFactory.getLogger(ProcessFunctionServiceImpl.class);

    @Autowired
    private SubjectProcessService subjectProcessService;

    @Override
    public List<ProcessFunction> getAllProcess(String bmpId){
        return BeanFactoryUtil.getBeansWithAnnotation(FunctionHandlerClass.class).entrySet().stream()
                .map(entry -> getProcessFunction(entry.getValue()))
                .filter(processFunction -> processFunction.getBmpIds().contains(bmpId))
                .collect(Collectors.toList());
    }

    @Override
    public List<ProcessFunction> getCustomProcess(String processId) {
        Process process = subjectProcessService.getProcess(processId);
        List<CustomProcess> subjectFunctions = subjectProcessService.selectProcessFlow(processId);
        //排序
        subjectFunctions.sort(Comparator.comparing(CustomProcess::getProcessOrder));
        List<ProcessFunction> allProcessFunction = getAllProcess(process.getBpmId());
        List<ProcessFunction> sortRealProcessFunction = new ArrayList<>();
        for (CustomProcess subjectFunction : subjectFunctions) {
            for (ProcessFunction processFunction : allProcessFunction) {
                if (processFunction.getProcessClass().equalsIgnoreCase(subjectFunction.getProcessClass())){
                    sortRealProcessFunction.add(processFunction);
                }
            }
        }
        return sortRealProcessFunction;
    }

    @Override
    @Transactional
    public String createProcess(String bmpId, Function<String,List<ProcessFlow>> initFunction){
        //生成流程
        String processId = subjectProcessService.createProcess(Process.ProcessBuilder
                .aProcess().withBpmId(bmpId).build(), initFunction);
        //获得主体所对应的方法
        List<ProcessFunction> functions = getCustomProcess(processId);
        List<ProcessSchedule> productFunctionList = functions.stream()
                .map(function -> ProcessSchedule.ProcessScheduleBuilder.aProcessSchedule()
                        .withProcessClass(function.getProcessClass()).withProcessName(function.getProcessName())
                        .withExecute(false).build())
                .collect(Collectors.toList());
        subjectProcessService.saveProcessSchedule(processId,productFunctionList);
        ProcessBaseSession processSession = new ProcessBaseSession();
        processSession.setProcessId(processId);
        subjectProcessService.saveProcessSession(processSession);
        return processId;
    }

    @Override
    public void cleanUnfinishedFunction() {
        List<ProcessFunction> needCleanProcessFunctions = BeanFactoryUtil
                .getBeansWithAnnotation(FunctionHandlerClass.class).values()
                .stream().map(this::getProcessFunction)
                .filter(processFunction -> Arrays.stream(processFunction.getNeedCleanStatus())
                        .noneMatch(status -> Objects.equals(DEFAULT_NEED_CLEAN_VALUE,status)))
                .collect(Collectors.toList());
        List<String> needCleanSubjects = subjectProcessService.getNeedCleanSubjects(needCleanProcessFunctions
                .stream().flatMap(function -> Arrays.stream(function.getNeedCleanStatus()).boxed())
                .collect(Collectors.toList()));
        needCleanProcessFunctions.forEach(function -> needCleanSubjects
                .forEach(processId -> ProcessDispatcher.findProcessHandler(function.getProcessClass()
                            , processId, ProcessDispatcher::executeFunction)));
    }

    private ProcessFunction getProcessFunction(Object object){
        Object target = AopTargetUtils.getTarget(object).orElseThrow(() -> { logger.error("流程类不存在:"+object);
        return new RuntimeException("流程类不存在:"+object); });
        FunctionHandlerClass functionHandlerClass = target.getClass().getAnnotation(FunctionHandlerClass.class);
        return ProcessFunction.ProcessFunctionBuilder.aProcessFunction()
                .withNeedCleanStatus(functionHandlerClass.needCleanStatus())
                .withProcessClass(target.getClass().getSimpleName())
                .withBmpIds(Stream.of(functionHandlerClass.bmpIds()).collect(Collectors.toList()))
                .withProcess(target)
                .withProcessName(functionHandlerClass.processName()).build();
    }
}
